package sk.lieskove.jianghongtiao.aresapi.response.obj;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import sk.lieskove.jianghongtiao.common.utils.xml.ProcessXML;

import javax.persistence.*;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.xpath.XPathExpressionException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="Odpoved" type="{http://wwwinfo.mfcr.cz/ares/xml_doc/schemas/ares/ares_datatypes/v_1.0.4}odpoved_fo" maxOccurs="unbounded"/>
 *         &lt;element name="Fault" type="{http://wwwinfo.mfcr.cz/ares/xml_doc/schemas/ares/ares_datatypes/v_1.0.4}chybova_odpoved" minOccurs="0"/>
 *       &lt;/sequence>
 *       &lt;attribute name="odpoved_datum_cas" use="required" type="{http://www.w3.org/2001/XMLSchema}dateTime" />
 *       &lt;attribute name="odpoved_typ" type="{http://wwwinfo.mfcr.cz/ares/xml_doc/schemas/ares/ares_datatypes/v_1.0.4}ares_dotaz_typ" fixed="fo" />
 *       &lt;attribute name="vystup_format" type="{http://wwwinfo.mfcr.cz/ares/xml_doc/schemas/ares/ares_datatypes/v_1.0.4}vystup_format" default="HTML" />
 *       &lt;attribute name="xslt" type="{http://wwwinfo.mfcr.cz/ares/xml_doc/schemas/ares/ares_datatypes/v_1.0.4}xslt_ks" default="klient" />
 *       &lt;attribute name="Id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@Entity
@Table(name="ares_odpovedi")
public class AresOdpovedi implements Serializable {

    @Id
    @GeneratedValue
    private Long dbId;
    private String id;
    @Enumerated(EnumType.STRING)
    private AresDotazTyp odpovedTyp;
    @Temporal(TemporalType.TIMESTAMP)
    private Date odpovedDatumCas;
    @Enumerated(EnumType.STRING)
    private VystupFormat vystupFormat;
    @Enumerated(EnumType.STRING)
    private XsltKs xslt;
    @OneToOne
    private ChybovaOdpoved fault;
    @OneToMany(mappedBy = "aresOdpovedi", cascade=CascadeType.PERSIST, fetch=FetchType.EAGER)
    private List<OdpovedFo> odpoved;
    @Transient
    private Document document;
    @Transient
    Logger log = Logger.getLogger(AresOdpovedi.class.getName());

    public AresOdpovedi() {
    }

    public AresOdpovedi(Document document) {
        processDocument(document);
    }

    private void setVystupFormat() {
        log.debug("Loading 'setVystupFormat'");
        try {
            Node outputFormat = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/@vystup_format", document);
            if (outputFormat == null) {
                log.warn("Cannot load: Ares_odpovedi/@vystup_format.");
            } else {
                vystupFormat = VystupFormat.fromValue(outputFormat.
                        getTextContent());
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load 'Ares_odpovedi/@vystup_format' property. ", ex);
        }
    }

    private void setOdpovedTyp() {
        log.debug("Loading 'setOdpovedTyp'");
        try {
            Node output = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/@odpoved_typ", document);
            if (output == null) {
                log.warn("Cannot load: Ares_odpovedi/@odpoved_typ");
            } else {
                odpovedTyp = AresDotazTyp.fromValue(output.getTextContent());
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load 'Ares_odpovedi/@odpoved_typ' property. ", ex);
        }
    }

    private void setId() {
        log.debug("Loading 'setId'");
        try {
            Node output = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/@Id", document);
            if (output == null) {
                log.warn("Cannot load: Ares_odpovedi/@Id");
            } else {
                id = output.getTextContent();
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load 'Ares_odpovedi/@Id' property. ", ex);
        }
    }

    private void setXsltKs() {
        log.debug("Loading 'setXsltKs'");
        try {
            Node output = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/@xslt", document);
            if (output == null) {
                log.warn("Cannot load: Ares_odpovedi/@xslt");
            } else {
                xslt = XsltKs.fromValue(output.getTextContent());
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load 'Ares_odpovedi/@xslt' property. ", ex);
        }
    }

    private void setOdpovedDatumCas() {
        log.debug("Loading 'setOdpovedDatumCas'");
        try {
            Node output = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/@odpoved_datum_cas", document);
            if (output == null) {
                log.warn("Cannot load: Ares_odpovedi/@odpoved_datum_cas");
            } else {
                DateTime date = new DateTime(output.getTextContent());
                odpovedDatumCas = date.toDate();
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load 'Ares_odpovedi/@odpoved_datum_cas' property. ",
                    ex);
        }
    }

    private void setFault() {
        log.debug("Loading 'setFault'");
        try {
            Node faultcode = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/Fault/faultcode", document);
            Node faultstring = ProcessXML.getNodeByXPathQuery(
                    "Ares_odpovedi/Fault/faultstring", document);

            if ((faultcode != null) && (faultstring != null)) {
                fault = new ChybovaOdpoved(faultcode.getTextContent(),
                        faultstring.getTextContent());
                fault.setAresOdpovedi(this);
            }
        } catch (XPathExpressionException ex) {
            log.warn(
                    "Cannot load: Ares_odpovedi/Fault/faultcode or Ares_odpovedi/Fault/faultstring",
                    ex);
        }
    }

    private void setOdpoved() {
        log.debug("Loading 'setOdpoved'");
        odpoved = new ArrayList<OdpovedFo>();
        try {
            String xPath = "Ares_odpovedi/Odpoved";
            NodeList odpovede = ProcessXML.getNodeListByXPathQuery(xPath, document);
            if (odpovede != null) {
                for (int i = 0; i < odpovede.getLength(); i++) {
                    Node o = odpovede.item(i);
                    OdpovedFo odpovedFo = new OdpovedFo(xPath, i+1, o, document);
                    odpovedFo.setAresOdpovedi(this);
                    odpoved.add(odpovedFo);
                }
            } else {
                log.warn("Cannot load: Ares_odpovedi/Odpoved");
            }
        } catch (XPathExpressionException ex) {
            log.warn("Cannot load: Ares_odpovedi/Odpoved", ex);
        }
    }

    private void processDocument(Document document) {
        this.document = document;
        setVystupFormat();
        setOdpovedTyp();
        setId();
        setXsltKs();
        setOdpovedDatumCas();
        setFault();
        setOdpoved();
    }

    /**
     * Gets the value of the odpoved property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the odpoved property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getOdpoved().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link OdpovedFo }
     * 
     * 
     */
    public List<OdpovedFo> getOdpoved() {
        if (odpoved == null) {
            odpoved = new ArrayList<OdpovedFo>();
        }
        return this.odpoved;
    }

    /**
     * Gets the value of the fault property.
     * 
     * @return
     *     possible object is
     *     {@link ChybovaOdpoved }
     *     
     */
    public ChybovaOdpoved getFault() {
        return fault;
    }

    /**
     * Sets the value of the fault property.
     * 
     * @param value
     *     allowed object is
     *     {@link ChybovaOdpoved }
     *     
     */
    public void setFault(ChybovaOdpoved value) {
        this.fault = value;
    }

    /**
     * Gets the value of the odpovedDatumCas property.
     * 
     * @return
     *     possible object is
     *     {@link XMLGregorianCalendar }
     *     
     */
    public Date getOdpovedDatumCas() {
        return odpovedDatumCas;
    }

    /**
     * Sets the value of the odpovedDatumCas property.
     * 
     * @param value
     *     allowed object is
     *     {@link XMLGregorianCalendar }
     *     
     */
    public void setOdpovedDatumCas(Date value) {
        this.odpovedDatumCas = value;
    }

    /**
     * Gets the value of the odpovedTyp property.
     * 
     * @return
     *     possible object is
     *     {@link AresDotazTyp }
     *     
     */
    public AresDotazTyp getOdpovedTyp() {
        if (odpovedTyp == null) {
            return AresDotazTyp.FO;
        } else {
            return odpovedTyp;
        }
    }

    /**
     * Sets the value of the odpovedTyp property.
     * 
     * @param value
     *     allowed object is
     *     {@link AresDotazTyp }
     *     
     */
    public void setOdpovedTyp(AresDotazTyp value) {
        this.odpovedTyp = value;
    }

    /**
     * Gets the value of the vystupFormat property.
     * 
     * @return
     *     possible object is
     *     {@link VystupFormat }
     *     
     */
    public VystupFormat getVystupFormat() {
        if (vystupFormat == null) {
            return VystupFormat.HTML;
        } else {
            return vystupFormat;
        }
    }

    /**
     * Sets the value of the vystupFormat property.
     * 
     * @param value
     *     allowed object is
     *     {@link VystupFormat }
     *     
     */
    public void setVystupFormat(VystupFormat value) {
        this.vystupFormat = value;
    }

    /**
     * Gets the value of the xslt property.
     * 
     * @return
     *     possible object is
     *     {@link XsltKs }
     *     
     */
    public XsltKs getXslt() {
        if (xslt == null) {
            return XsltKs.KLIENT;
        } else {
            return xslt;
        }
    }

    /**
     * Sets the value of the xslt property.
     * 
     * @param value
     *     allowed object is
     *     {@link XsltKs }
     *     
     */
    public void setXslt(XsltKs value) {
        this.xslt = value;
    }

    /**
     * Gets the value of the id property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setId(String value) {
        this.id = value;
    }

    public Long getDbId() {
        return dbId;
    }

    public void setDbId(Long dbId) {
        this.dbId = dbId;
    }
    
}
